import socket

from utils import logging, structure_reqeust, parse_packet


class BaseHandler(object):
    split_text = "&|&"
    recv_len = 15

    def __init__(self, parent, client: socket.socket, address: tuple):
        logging.info("连接成功 {}:{}".format(address[0], address[1]))

        self.parent = parent
        self.__socket = client
        self.remote_address = address

        self.is_connection = True

    def on_message(self, data: bytes):
        """
        有信息来的回调函数

        :param data:
        :return:
        """

        data_type, data, err = self.parse_packet(data)
        if err:
            logging.info(data.decode())
            return False

        data_type = data_type.decode()
        data = data.decode()

        self.handle(data_type, data)

    def parse_packet(self, data: bytes) -> (bytes, bytes, bool):

        """
        解析数据包得到完整的数据

        :param data:    接收到的信息
        :return:        返回完整的数据
        """

        # 解析数据头
        data_type, data_len, data, over_len, err = parse_packet(data, self.split_text, self.recv_len)
        if err:
            return 'error', b"Bad request.", True

        # 如果计算的结果大于 0 证明还有剩下的数据 将剩下的数据拿到
        if over_len > 0:
            over_data = self.__socket.recv(over_len)

            # 相加得到完整的数据
            data = data + over_data

        return data_type, data, False

    def on_connect_err(self, err_type: str, descriotion: str):
        """
        链接发生错误

        :param err_type:
        :param descriotion:
        :return:
        """
        # 调用父类, 删除当前客户端
        logging.info(descriotion)
        self.close_connnect()
        self.parent.on_disconnection(self.remote_address)

    def handle(self, data_type: str, data: str):
        """
        处理信息方法, 自己继承重写

        :param data_type:
        :param data:
        :return:
        """

        raise ReferenceError("处理信息方法, 自己继承重写")

    def send(self, data_type: str, data: str):
        self.__socket.send(structure_reqeust(data_type = data_type, data = data))

    def close_connnect(self):
        self.is_connection = False

        try:
            self.__socket.close()
        except Exception:
            pass
